package com.ewei.web.common.exception;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver;

import com.ewei.web.common.response.ExceptionVO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
 * 自定义错误处理
 * @author David
 *
 */
public class ExceptionHandlerResolver extends AbstractHandlerMethodExceptionResolver {
	private static final Logger logger = LogManager.getLogger(ExceptionHandlerResolver.class);
	private String exceptionAttributeName = "exception";
	private String defaultMessage = "{\"status\":\"88888\",\"exceptionMessage\":\"系统内部处理异常\"}";//默认信息
	private String errorPage = "error";//错误页面
	private Map<String,String> exceptionResolvers = new HashMap<String,String>();
	
	public String getExceptionAttributeName() {
		return exceptionAttributeName;
	}
	public void setExceptionAttributeName(String exceptionAttributeName) {
		this.exceptionAttributeName = exceptionAttributeName;
	}
	public String getDefaultMessage() {
		return defaultMessage;
	}
	public void setDefaultMessage(String defaultMessage) {
		this.defaultMessage = defaultMessage;
	}
	public String getErrorPage() {
		return errorPage;
	}
	public void setErrorPage(String errorPage) {
		this.errorPage = errorPage;
	}
	public Map<String, String> getExceptionResolvers() {
		return exceptionResolvers;
	}
	public void setExceptionResolvers(Map<String, String> exceptionResolvers) {
		this.exceptionResolvers = exceptionResolvers;
	}
	private ExceptionVO getErrorResponse(HandlerMethod handlerMethod,Exception ex){
		ExceptionVO exceptionVO = null;
		ObjectMapper mapper  = new ObjectMapper();
		try{
			Set<Entry<String,String>> entrySet = exceptionResolvers.entrySet();
			for(Entry<String,String> entry:entrySet){
				String clzName = entry.getKey();
				String message = entry.getValue();
				if(ex.getClass()==Class.forName(clzName)){
					exceptionVO = mapper.readValue(message,ExceptionVO.class);
					break;
				}
			}
			if(null == exceptionVO){//默认异常信息
				exceptionVO = mapper.readValue(defaultMessage, ExceptionVO.class);
			}
			exceptionVO.setExceptionMethod(handlerMethod.getMethod().getName());
			exceptionVO.setExceptionClass(ex.getClass().getName());
		}catch(Exception e){
			logger.info(e);
		}
		return exceptionVO;
	}
	@Override
	protected ModelAndView doResolveHandlerMethodException(
			HttpServletRequest request, HttpServletResponse response,
			HandlerMethod handlerMethod, Exception ex) {
		logger.info(ex);
		ExceptionVO exceptionVO = getErrorResponse(handlerMethod, ex);
		response.setStatus(404);
		String contentType = null;
		if(isAjax(request)){//处理ajax请求
			contentType = "application/json;charset=UTF-8";
			ObjectMapper mapper = new ObjectMapper();
			try {
				String jsonResult = mapper.writer().writeValueAsString(exceptionVO);
				response.getOutputStream().println(jsonResult);
				response.setStatus(500);
			} catch (JsonProcessingException e) {
				logger.info(e);
			}catch(IOException ei){
				logger.info(ei);
			}
		}else{
			contentType="text/html;charset=UTF-8";
			logger.trace(ex.getMessage());
		}
		response.setContentType(contentType);
		exceptionVO.setContentType(contentType);
		return forward(request,response,exceptionVO);
	}
	private boolean isAjax(HttpServletRequest request){
		return request.getHeader("X-Requested-With") != null 
				&& "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
	}
	private ModelAndView forward(HttpServletRequest request,HttpServletResponse response,Object result){
		if(!isAjax(request)){
			ModelAndView model = new ModelAndView(errorPage);
			model.addObject(exceptionAttributeName,(ExceptionVO)result);
			return model;
		}
		return null;
	}
}
